package com.freedom.sql.jdbc.response;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowDatabasesStatement;
import com.freedom.sql.jdbc.netty.MyNioSocketChannel;
import com.freedom.sql.jdbc.utils.BufferAllocateUtils;
import com.freedom.sql.jdbc.utils.ByteUtils;
import com.freedom.sql.jdbc.utils.MyJsonProperties;

import io.netty.buffer.ByteBuf;

public class DatabasePacket {
	@SuppressWarnings("unused")
	private static final Logger logger = LogManager.getLogger(DatabasePacket.class);
	private MyNioSocketChannel channel;
	@SuppressWarnings("unused")
	private MySqlShowDatabasesStatement statement;
	private int packetSeq;

	public DatabasePacket(int _packetSeq, MyNioSocketChannel _channel, MySqlShowDatabasesStatement _statement) {
		packetSeq = _packetSeq;
		channel = _channel;
		statement = _statement;
	}

	public void write() throws Exception {
		int totalLength = 0;
		//
		// header
		byte[] headerLen = ByteUtils.writeInt(1, 3);
		byte[] headerPacketId = { (byte) (++packetSeq) };
		byte[] headerNumberFields = { 1 };
		totalLength += 5;
		//
		// FieldPacket
		byte[] fieldLen = ByteUtils.writeInt(19, 3);
		byte[] fieldPacketId = { (byte) (++packetSeq) };
		byte[] fieldDetails = { 0, // catalog
				0, // db
				0, // table
				0, // orgTable
				0, // name
				0, // orgName
				(byte) 0x0C, //
				0, 0, // charsetIndex
				0, 0, 0, 0, // length
				(byte) (((byte) 253) & 0xff), // type
				0, 0, // flags
				0, // decimals
				0, 0,// fill

		};
		totalLength += 23;
		//
		// 开始写 eof
		byte[] eofLen = ByteUtils.writeInt(5, 3);
		byte[] eofPacketId = { (byte) (++packetSeq) };
		byte[] eofDetails = { (byte) 0xfe, //
				0, 0,// warningCount
		};
		byte[] eofStatus = ByteUtils.writeInt(2, 2);
		totalLength += 9;
		//
		// 开始构造我们需要的内容
		ArrayList<byte[]> dbBytesList = new ArrayList<byte[]>();
		int size;
		// String[] dbs = { "Hello", "World", "测试库0", "测试库1", "测试库2" };
		HashMap<String, ArrayList<String>> dbs = MyJsonProperties.getInstance().getDatabases();
		Set<String> dbKey = dbs.keySet();
		for (String db : dbKey) {
			byte[] dbNameBytes = ByteUtils.encode(db, channel.getCharset());
			size = (dbNameBytes == null || dbNameBytes.length == 0) ? 1 : ByteUtils.getVarLength(dbNameBytes);
			dbBytesList.add(ByteUtils.writeInt(size, 3));
			dbBytesList.add(ByteUtils.writeInt(++packetSeq, 1));
			// 添加长度
			if (dbNameBytes.length < 251) {
				dbBytesList.add(ByteUtils.writeByte((byte) dbNameBytes.length, 1));
			} else if (dbNameBytes.length < 0x10000L) {
				dbBytesList.add(ByteUtils.writeByte((byte) 252, 1));
				dbBytesList.add(ByteUtils.writeInt(dbNameBytes.length, 2));
			} else if (dbNameBytes.length < 0x1000000L) {
				dbBytesList.add(ByteUtils.writeByte((byte) 253, 1));
				dbBytesList.add(ByteUtils.writeInt(dbNameBytes.length, 3));
			} else {
				dbBytesList.add(ByteUtils.writeByte((byte) 254, 1));
				dbBytesList.add(ByteUtils.writeInt(dbNameBytes.length, 8));
			}
			// 添加内容
			dbBytesList.add(dbNameBytes);
		}
		for (byte[] content : dbBytesList) {
			totalLength += content.length;
		}
		//
		// 最后的eof
		byte[] lastEofLen = ByteUtils.writeInt(5, 3);
		byte[] lastEofPacketId = { (byte) (++packetSeq) };
		byte[] lastEofDetails = { (byte) 0xfe, //
				0, 0,// warningCount
		};
		byte[] lastEofstatus = ByteUtils.writeInt(2, 2);
		totalLength += 9;
		// 开始合成
		ByteBuf finalBuf = BufferAllocateUtils.get(totalLength);
		finalBuf.writeBytes(headerLen);
		finalBuf.writeBytes(headerPacketId);
		finalBuf.writeBytes(headerNumberFields);
		finalBuf.writeBytes(fieldLen);
		finalBuf.writeBytes(fieldPacketId);
		finalBuf.writeBytes(fieldDetails);
		finalBuf.writeBytes(eofLen);
		finalBuf.writeBytes(eofPacketId);
		finalBuf.writeBytes(eofDetails);
		finalBuf.writeBytes(eofStatus);
		for (byte[] content : dbBytesList) {
			finalBuf.writeBytes(content);
		}
		finalBuf.writeBytes(lastEofLen);
		finalBuf.writeBytes(lastEofPacketId);
		finalBuf.writeBytes(lastEofDetails);
		finalBuf.writeBytes(lastEofstatus);
		channel.writeAndFlush(finalBuf);
	}
}
